package com.ictravi.iamunit.connector;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.ictravi.iamunit.IAMUnitException;
import com.ictravi.iamunit.IAMUnitTestCase;

public abstract class AbstractConnector implements Connector {
	Map<String, Method> methods = new TreeMap<String, Method>(
			String.CASE_INSENSITIVE_ORDER);
	private static Log LOG = LogFactory.getLog(IAMUnitTestCase.class);

	public AbstractConnector() {
		LOG.debug("...in: abstractConnector");

		Method[] allMethods = getClass().getMethods();
		for (Method m : allMethods) {
			if (m.getName().startsWith("op") == false) {
				continue;
			}

			if (m.getGenericReturnType() != void.class) {
				continue;
			}

			Type[] paramTypes = m.getGenericParameterTypes();
			if (paramTypes.length != 1
					|| Map.class.isAssignableFrom(paramTypes[0].getClass())) {
				continue;
			}

			methods.put(m.getName(), m);
		}
	}

	public void tearDown() throws IAMUnitException {
	}

	public void execute(String operation, Map<String, Collection<String>> data)
			throws IAMUnitException {
		String methodName = "op" + operation;
		Method m = methods.get(methodName);
		if (m == null) {
			throw new IAMUnitException("Invalid operation '" + operation + "'");
		}

		Object[] args = { data };
		try {
			m.invoke(this, args);
		} catch (InvocationTargetException e) {
			Throwable cause = e.getCause();
			if (cause instanceof Error) {
				throw (Error) cause;
			} else if (cause instanceof IAMUnitException) {
				throw (IAMUnitException) cause;
			}

			throw new IAMUnitException(cause);
		} catch (IllegalArgumentException e) {
			throw new IAMUnitException(e);
		} catch (IllegalAccessException e) {
			throw new IAMUnitException(e);
		}
	}

	protected static String getFirstValue(
			Map<String, Collection<String>> attrs, String attrName) {
		Collection<String> values = attrs.get(attrName);
		if (values == null) {
			return null;
		} else {
			Iterator<String> i = values.iterator();

			if (i.hasNext()) {
				return i.next();
			} else {
				return null;
			}
		}
	}

	protected static String getSingleValue(
			Map<String, Collection<String>> attrs, String attrName)
			throws IAMUnitException {
		Collection<String> values = attrs.get(attrName);
		if (values == null) {
			return null;
		}

		if (values.size() > 1) {
			throw new IAMUnitException(
					"Error: '"
							+ attrName
							+ "' is single valued but more than one value was specified.");
		}

		Iterator<String> i = values.iterator();
		if (i.hasNext()) {
			return i.next();
		} else {
			return null;
		}
	}
}